package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"time"
)

type GithubUser struct {
	Login string `json:"login"`
}

var (
	RECORD_FILE_PATH = "follower.json"
	OUTPUT_FILE_PATH = "output.txt"


)


func queryRecord(username string) ([]GithubUser, error) {
	var url string
	page := 1
	var res []GithubUser

	for {
		url = fmt.Sprintf("https://api.github.com/users/%s/followers?per_page=20&page=%d", username, page)
		fmt.Println(url)
		resp, err := http.Get(url)
		if err != nil {
			return nil, err
		}

		defer resp.Body.Close()

		body, err := io.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}

		var tmp []GithubUser

		err = json.Unmarshal(body, &tmp)

		if err != nil {
			return nil, err
		}

		if len(tmp) == 0 {
			break
		}

		res = append(res, tmp...)
		page++
		if (page == 10) {
			break // record 10 page ?
		}
	}

	return res, nil
}



func readRecord() ([]GithubUser, error){
	data, err := os.ReadFile(RECORD_FILE_PATH)
	if err != nil {
		return nil, err
	}

	var res []GithubUser
	err = json.Unmarshal(data, &res)
	if err != nil {
		return nil, err
	}

	return res, nil
}



func saveRecord(users []GithubUser) error {
	data, err := json.Marshal(users)
	if err != nil {
		return err
	}

	os.WriteFile(RECORD_FILE_PATH, data, 0644)

	return nil 
}

func writeUnfollowLog(f *os.File, username string) error {
	now := time.Now().UTC()

	_, err := f.Write([]byte(fmt.Sprintf(
		"User %s unfollowed provided github user\t\t\t|\t%s\n",
		username,
		now.Format("YYYY-MM-DD"),
	)))

	return err
}

func convert2Map(users []GithubUser) map[string] bool {
	res := map[string]bool{}
	for _, u := range users {
		res[u.Login] = true
	}

	return res
}

func main() {
	username := os.Getenv("GITHUB_USERNAME")

	log := log.New(os.Stdout, "LONGGING: ", log.LstdFlags | log.Lmicroseconds | log.Lshortfile)

	log.Println("Starting generate output to file `output.txt`")
	defer log.Println("LOGGING: DONE")

	var err error
	var follower, record []GithubUser
	if follower, err = queryRecord(username); err != nil {
		log.Fatal(err)
	}

	if record, err = readRecord(); err != nil {
		log.Fatal(err)
	}

	newMap, oldMap := convert2Map(follower), convert2Map(record)

	// I dont like append
	outputfile, err := os.OpenFile(OUTPUT_FILE_PATH, os.O_TRUNC | os.O_CREATE | os.O_WRONLY, 0644)

	if err != nil {
		log.Fatal(err)
	}

	defer outputfile.Close()

	for k := range oldMap {
		if _, exist := newMap[k]; !exist {
			if err := writeUnfollowLog(outputfile, k); err != nil {
				log.Println(err)
			}
		}
	}

	if err = saveRecord(follower); err != nil {
		log.Fatal(err)
	}
}

